package _5_multithread._1_basic;

import java.util.concurrent.locks.LockSupport;

/**
 * @author bpzj 2019/11/27 16:54
 */
public class _2_Sleep_Wait_LockSupport {

  /** {@link Object#wait()}  {@link Thread#sleep(long)}
   * <pre>
   * Thread.sleep 是 static 方法
   *    所以, t1.sleep() 实际上相当于 Thread.sleep() 这样调用。
   *          sleep() 是在调用 Thread.sleep() 方法的线程中暂停, 阻塞住。
   *
   * wait: Object 的实例方法，This method causes the current thread to place itself
   *                         in the wait set for this object and then to relinquish
   *                         any and all synchronization claims on this object.
   *    当前线程放弃 "对象锁"，进入此 "锁对象" 的**等待锁定池**,
   *    等待 notify/ notifyAll/ 超时  之后, 尝试再次获取锁, 向下执行
   *    所以，wait 需要在 synchronized 代码块中使用，否则，没有被锁定的对象
   *
   * LockSupport.park / unpark 方法, 改变的与线程关联的一个_count值, 不用像 wait 方法一样，要先获取对象锁，才能在同步代码块里使用
   *    LockSupport.park()可以在任意地方执行；
   *    LockSupport.park()不需要捕获中断异常；
   *    一个线程 park后, 可以用另一个线程执行 unpark() 来唤醒，unpark要求指定线程
   *    park()/unpark()底层的原理是 "二元信号量"，你可以把它相像成只有一个许可证的Semaphore，
   *    只不过这个信号量在重复执行 unpark()的时候也不会再增加许可证，最多只有一个许可证。
   *
   *    LockSupport.park() 会释放锁资源吗?
   *      不会，它只负责阻塞当前线程，释放锁资源实际上是在Condition的await()方法中实现的。
   * </pre>
   */
  public static void main(String[] args) throws InterruptedException {
    _2_Sleep_Wait_LockSupport t1 = new _2_Sleep_Wait_LockSupport();
    t1.testSleep();
    System.out.println("---------------------------");
    usePark();
  }

  private void testSleep() throws InterruptedException {
    Thread t1 = new Thread(new T1(), "t1");
    long start = System.currentTimeMillis();
    t1.start();
    t1.sleep(500);  // 即使是这样写, 编译之后也是 Thread.sleep(500);
    Thread.sleep(500);
    System.out.println(Thread.currentThread() + "：阻塞了" + (System.currentTimeMillis() - start) + "毫秒");
  }

  public class T1 implements Runnable {
    @Override
    public void run() {
      synchronized (this) {
        System.out.println(Thread.currentThread()+": 获取到锁");
        try {
          this.wait(3000);
        } catch (InterruptedException e) {}
        System.out.println(Thread.currentThread() + ": 即将结束");
      }
    }
  }

  public static void usePark() {
    Thread t2 = new Thread(new Runnable() {
      @Override
      public void run() {
        LockSupport.park();
        System.out.println("t1线程不在park了");
      }
    });
    t2.start();
    System.out.println(Thread.currentThread()+": 将要调用 unpark(t1)");
    LockSupport.unpark(t2);
  }
}
